/*
 * Copyright © 2017 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */
package cn.hermit.core;

/**
 * An array-based stack implementation.
 * 
 * @param T
 * 		Object type in stack
 * 
 * @author Jack Gao (Chinese name : GAO JIANGUO, Email : linux.gjg@gmail.com)
 * @date 13 Jun, 2014
 * 
 */
@SuppressWarnings("unchecked")
public final class FastStack<T> {

	/**
	 * Inner array to store elements for stack.
	 */
	private Object[] stack;
	/**
	 * The pointer point to top of stack.
	 */
	private int pointer;

	/**
	 * Constructor with default initial capacity 10.
	 */
	public FastStack() {
		this(10);
	}

	/**
	 * Constructor with initial capacity.
	 * 
	 * @param initialCapacity
	 * 		Initial capacity of stack
	 */
	public FastStack(int initialCapacity) {
		stack = new Object[initialCapacity];
	}

	/**
	 * Push an element into stack.
	 * 
	 * @param value
	 * 		An element to push.
	 * @return
	 * 		The element pushed into stack
	 */
	public T push(T value) {
		if (pointer + 1 >= stack.length) {
			resizeStack(stack.length * 2);
		}
		stack[pointer++] = value;
		return value;
	}

	/**
	 * Pop out the element on top without return for the top element.
	 */
	public void popSilently() {
		stack[--pointer] = null;
	}

	/**
	 * Pop out the element on top.
	 * @return
	 * 		The top element.
	 */
	public T pop() {
		final T result = (T) stack[--pointer];
		stack[pointer] = null;
		return result;
	}

	/**
	 * Get element on top.
	 * 
	 * @return
	 * 		The top element in stack
	 */
	public T peek() {
		return pointer == 0 ? null : (T) stack[pointer - 1];
	}

	/**
	 * Replace an element on top in stack.
	 * 
	 * @param value
	 * 		An element to replace with
	 * @return
	 * 		The replaced element.
	 */
	public T replace(T value) {
		final T result = (T) stack[pointer - 1];
		stack[pointer - 1] = value;
		return result;
	}

	/**
	 * Replace an element on top in stack without return for the replaced element.
	 * 
	 * @param value
	 * 		An element to replace with.
	 */
	public void replaceSilently(T value) {
		stack[pointer - 1] = value;
	}

	/**
	 * @return
	 * 		Size of the stack
	 */
	public int size() {
		return pointer;
	}

	/**
	 * Check if there is any element in stack.
	 * @return
	 */
	public boolean hasStuff() {
		return pointer > 0;
	}

	// public Object get(int i) {
	// return stack[i];
	// }

	private void resizeStack(int newCapacity) {
		Object[] newStack = new Object[newCapacity];
		System.arraycopy(stack, 0, newStack, 0, Math.min(pointer, newCapacity));
		stack = newStack;
	}
	
	/**
	 * Print elements in stack by order
	 */
	public String toString() {
		StringBuffer result = new StringBuffer("[");
		for (int i = 0; i < pointer; i++) {
			if (i > 0) {
				result.append(", ");
			}
			result.append(stack[i]);
		}
		result.append(']');
		return result.toString();
	}
}